﻿using mozhi.smarterp.Business.Enums;
using mozhi.smarterp.Business.Purchases.Receipt;
using mozhi.smarterp.Business.Purchases.Repositories;
using mozhi.smarterp.Business.Purchases.Services;
using Mozhi.Abp.Domain.AuthorCenter;
using Mozhi.Abp.Domain.BasicData;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;

namespace mozhi.smarterp.Business.Purchases.Receipit
{
    public class PurchaseReceiptAppService : BusinessAppService, IPurchaseReceiptAppService
    {
        private IPurchaseReceiptRepository _repository;
        private PurchaseReceiptManager _manager;
        private ISupplierRepository _supplierRepository;
        private IDepartmentRepository _departmentRepository;
        private IUnitRepository _unitRepository;
        private IProductAuxiliaryUnitRepository _auxiliaryUnitRepository;
        private IProductRepository _productRepository;
        private IEmployeeRepository _employeeRepository;
        private ICurrencyRepository _currencyRepository;

        public PurchaseReceiptAppService(IPurchaseReceiptRepository repository, PurchaseReceiptManager manager,
            IProductRepository productRepository, IEmployeeRepository employeeRepository , ISupplierRepository supplierRepository , IDepartmentRepository departmentRepository , 
            IProductAuxiliaryUnitRepository auxiliaryUnitRepository , IUnitRepository unitRepository , ICurrencyRepository currencyRepository)
        {
            _repository = repository;
            _manager = manager;
            _productRepository = productRepository;
            _employeeRepository = employeeRepository;
            _supplierRepository = supplierRepository;
            _departmentRepository = departmentRepository;
            _unitRepository = unitRepository;
            _auxiliaryUnitRepository = auxiliaryUnitRepository;
            _currencyRepository = currencyRepository;
        }

        public async Task<PurchaseReceiptDto> CreateAsync(PurchaseReceiptCreateDto input)
        {
            var receipt = await _manager.GetAsync(null, input.DepartmentId, input.WarehouseClerkId, input.Date, input.Comment, input.PaymentTemrId, input.CurrencyId, input.ExchangeRate, input.IncludeTax,
                input.PurchaseDepartmentId, input.PurchaserId, input.SupplierId);

            input.Items = input.Items ?? new List<PurchaseReceiptItemCreateDto>();

            var receiptItems = new List<PurchaseReceiptItem>();

            foreach (var item in receipt.Items)
            {
                var receiptItem = await _manager.GetItemAsync(null, item.ProductId, item.WarehouseId, item.LocationId, item.PurchaseUnitId, item.ReceivableQuantity, item.AuxiliaryQuantity, item.BasicQuantity,
                    item.Price, item.TaxRateId, item.BatchNumber, item.SerialNumber, item.ProductionDate, item.IsGift, item.Remark);

                receiptItems.Add(receiptItem);
            }

            receipt.ChangeItems(receiptItems);

            receipt = await _repository.InsertAsync(receipt);

            var result = ObjectMapper.Map<PurchaseReceipt , PurchaseReceiptDto>(receipt);

            await LoadOtherInfoAsync(new List<PurchaseReceiptDto>() { result });

            return result;
        }

        public async Task DeleteAsync(Guid id)
        {
            await _manager.DeleteAsync(id);
        }

        public async Task<PurchaseReceiptDto> GetAsync(Guid id)
        {
            var receipt = await _repository.GetAsync(id);

            var result = ObjectMapper.Map<PurchaseReceipt, PurchaseReceiptDto>(receipt);

            await LoadOtherInfoAsync(new List<PurchaseReceiptDto>() { result });

            return result;
        }

        public async Task<PagedResultDto<PurchaseReceiptDto>> GetListAsync(PagedAndSortedResultRequestDto filter)
        {
            var receipts = await _repository.GetPagedListAsync(filter.SkipCount, filter.MaxResultCount, filter.Sorting);

            var count = await _repository.GetCountAsync();

            var result = new PagedResultDto<PurchaseReceiptDto>()
            {
                Items = ObjectMapper.Map<List<PurchaseReceipt>, List<PurchaseReceiptDto>>(receipts),
                TotalCount = count
            };

            await LoadOtherInfoAsync(result.Items.ToList());

            return result;
        }

        public async Task<PurchaseReceiptDto> UpdateAsync(PurchaseReceiptUpdateDto input)
        {
            var receipt = await _manager.GetAsync(input.Id, input.DepartmentId, input.WarehouseClerkId, input.Date, input.Comment, input.PaymentTemrId, input.CurrencyId, input.ExchangeRate, input.IncludeTax,
               input.PurchaseDepartmentId, input.PurchaserId, input.SupplierId);

            input.Items = input.Items ?? new List<PurchaseReceiptItemUpdateDto>();

            var receiptItems = new List<PurchaseReceiptItem>();

            foreach (var item in receipt.Items)
            {
                var receiptItem = await _manager.GetItemAsync(item.Id, item.ProductId, item.WarehouseId, item.LocationId, item.PurchaseUnitId, item.ReceivableQuantity, item.AuxiliaryQuantity, item.BasicQuantity,
                    item.Price, item.TaxRateId, item.BatchNumber, item.SerialNumber, item.ProductionDate, item.IsGift, item.Remark);

                receiptItems.Add(receiptItem);
            }

            receipt.ChangeItems(receiptItems);

            receipt = await _repository.InsertAsync(receipt);

            var result = ObjectMapper.Map<PurchaseReceipt, PurchaseReceiptDto>(receipt);

            await LoadOtherInfoAsync(new List<PurchaseReceiptDto>() { result });

            return result;
        }

        public async Task UpdateStatusAsync(Guid id, DocumentStatusType status)
        {
            await _manager.UpdateStatusAsync(id, status);
        }

        #region
        private async Task LoadOtherInfoAsync(List<PurchaseReceiptDto> receipts)
        {
            if (receipts.IsNullOrEmpty())
                return;

            foreach (var receipt in receipts)
            {
                var supplier = await _supplierRepository.GetAsync(receipt.SupplierId);
                var department = receipt.DepartmentId.HasValue && receipt.DepartmentId.Value != default ? await _departmentRepository.GetAsync(receipt.DepartmentId.Value) : null;
                var purchaseDepartment = await _departmentRepository.GetAsync(receipt.PurchaseDepartmentId);
                var currency = await _currencyRepository.GetAsync(receipt.CurrencyId);

                var purchaser = receipt.PurchaserId != default ? await _employeeRepository.GetAsync(receipt.PurchaserId) : null;
                var warhouseClerk = receipt.WarehouseClerkId != default ? await _employeeRepository.GetAsync(receipt.WarehouseClerkId) : null;

                receipt.SupplierName = supplier?.Name;
                receipt.PurchaserName = purchaser?.Name;
                receipt.PurchaseDepartmentName = purchaseDepartment?.Name;
                receipt.CurrencyName = currency?.Name;
                receipt.WarehouseClerkName = warhouseClerk?.Name;

                foreach (var receiptItem in receipt.Items)
                {
                    var product = await _productRepository.GetAsync(receiptItem.ProductId);

                    var purchaseUnit = await _unitRepository.GetAsync(receiptItem.PurchaseUnitId);

                    var basicUnit = await _unitRepository.GetAsync(receiptItem.BasicUnitId);

                    receiptItem.ProductCode = product?.Code;
                    receiptItem.ProductName = product?.Name;
                    receiptItem.ProductModel = product?.Model;
                    receiptItem.PurchaseUnitName = purchaseUnit?.Name;
                    receiptItem.BasicUnitName = basicUnit?.Name;
                }
            }
        }
        #endregion
    }
}
